﻿#region Using Directives

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Csla;

using MarketPulse.BusinessLogic.Core.Security;
using MarketPulse.BusinessLogic.Core.Criteria;


#endregion

namespace MarketPulse.BusinessLogic.Core.System
{
    /// <summary>
    /// This class represents a profile and properties stored for the lifetime of an application.
    /// </summary>
    [Serializable]
    [Csla.Server.ObjectFactory("MarketPulse.DataAccess.Factory.ApplicationProfileFactory, MarketPulse.DataAccess.Factory", "Fetch")]
    public class ApplicationProfile : MarketPulseBase<ApplicationProfile>
    {
        // TODO: When functionality needs to come into the base ApplicationProfile
        //       move what is required from the ReportingApplicationProfile.
        #region Contructors

            /// <summary>
            /// default constructor is private in order to (try to) enforce construction
            /// only via the static factory methods provided.
            /// </summary>
            private ApplicationProfile()
            {
            }

        #endregion

        #region Methods

            #region Factory Methods

                /// <summary>
                /// Method that creates a new ApplicationProfile via the DataPortal client proxy
                /// </summary>
                /// <returns>The newly created ApplicationProfile object</returns>
                public static ApplicationProfile New()
                {
                    return DataPortal.Create<ApplicationProfile>();
                }

                /// <summary>
                /// Method used to retrieve a filled ApplicationProfile object.
                /// </summary>
                /// <param name="username">The username to retrieve the ApplicationProfile for.</param>
                /// <param name="profileTypeGuid">The GUID of the ProfileType to retrieve the ApplicationProfile for.</param>
                /// <returns></returns>
                public static ApplicationProfile Get(string username, Guid profileTypeGuid)
                {
                    return DataPortal.Fetch<ApplicationProfile>(new UsernameAndProfileTypeGUIDCriteria(username, profileTypeGuid));
                }

                /// <summary>
                /// Method used to retrieve a filled ApplicationProfile object.
                /// </summary>
                /// <param name="userGUID">The GUID of the User to retrieve the ApplicationProfile for.</param>
                /// <param name="profileTypeGuid">The GUID of the ProfileType to retrieve the ApplicationProfile for.</param>
                /// <returns></returns>
                public static ApplicationProfile Get(Guid userGUID, Guid profileTypeGuid)
                {
                    return DataPortal.Fetch<ApplicationProfile>(new UserGUIDAndProfileTypeGUIDCriteria(userGUID, profileTypeGuid));
                }

            #endregion

            #region Business Process Methods

                /// <summary>
                /// Method used to add contact details
                /// </summary>
                /// <param name="contactDetailsGuid"></param>
                /// <param name="contactDetailsLabel"></param>
                /// <param name="apartmentOrFloorNumber"></param>
                /// <param name="houseNameOrNumber"></param>
                /// <param name="addressLine1"></param>
                /// <param name="addressLine2"></param>
                /// <param name="addressLine3"></param>
                /// <param name="addressLine4"></param>
                /// <param name="addressLine5"></param>
                /// <param name="postCode"></param>
                /// <param name="latitude"></param>
                /// <param name="longtitude"></param>
                public void AddContactDetails(Guid areaGUID, Guid countryGUID, string contactDetailsLabel, string apartmentOrFloorNumber, string houseNameOrNumber, string addressLine1, string addressLine2, string addressLine3, string addressLine4, string addressLine5, string postCode, string phone, long latitude, long longtitude)
                {
            
                    ContactDetails.AreaGUID = areaGUID;
                    ContactDetails.CountryGUID = countryGUID;
                    ContactDetails.ContactDetailsLabel = contactDetailsLabel;
                    ContactDetails.ApartmentOrFloorNumber = apartmentOrFloorNumber;
                    ContactDetails.HouseNameOrNumber = houseNameOrNumber;
                    ContactDetails.AddressLine1 = addressLine1;
                    ContactDetails.AddressLine2 = addressLine2;
                    ContactDetails.AddressLine3 = addressLine3;
                    ContactDetails.AddressLine4 = addressLine4;
                    ContactDetails.AddressLine5 = addressLine5;
                    ContactDetails.PostCode = postCode;
                    ContactDetails.Phone = phone;
                    ContactDetails.Latitude = latitude;
                    ContactDetails.Longtitude = longtitude;

                }

                /// <summary>
                /// Method used to set the AreaGUID for this class
                /// </summary>
                /// <param name="areaGUID">The GUID of the area</param>
                public void SetArea(Guid areaGUID)
                {
                    ContactDetails.AreaGUID = areaGUID;
                }

                /// <summary>
                /// Method used to retrieve the ContactDetails for the user associated with this profile
                /// </summary>
                /// <returns>A valid (populated) Contact Details object</returns>
                public ContactDetails GetContactDetails()
                {
                    return ContactDetails;
                }

                /// <summary>
                /// Method used to set the ContactDetails for the user associated with this profile
                /// </summary>
                public void SetContactDetails(ContactDetails details)
                {
                    ContactDetails = details;
                }

                /// <summary>
                /// Method used to set the users password using an MD5 ecoding algorithm
                /// </summary>
                /// <param name="password">The password to use</param>
                public void SetPassword(string password)
                {
                    this.Password = MarketPulseSecurity.StringToMD5(password);
                }

                /// <summary>
                /// Method used to set the users password using a SHA1 encryption algorithm
                /// </summary>
                /// <param name="password">The password to use</param>
                /// <param name="salt">The salt value to use as part of the enrcyption</param>
                public void SetPassword(string password, string salt)
                {
                    this.Password = MarketPulseSecurity.StringToSHA1(password, salt);
                }

                /// <summary>
                /// Method used to change a users password
                /// </summary>
                /// <param name="oldPassword">The old password to validate the password change</param>
                /// <param name="newPassword">The new password to set</param>
                /// <param name="confirmNewPassword">A confirmation of the new password to set</param>
                public void ChangePassword(string oldPassword, string newPassword, string confirmNewPassword)
                {
                    if (MarketPulseSecurity.StringToMD5(oldPassword) != Password)
                    {
                        throw new Exception("Old password value was incorrect");
                    }

                    if (newPassword == confirmNewPassword)
                    {
                        Password = MarketPulseSecurity.StringToMD5(newPassword);

                        Save();
                    }
                    else
                    {
                        throw new Exception("New password values did not match");
                    }
                }

            #endregion

        #endregion

        #region Properties

            /// <summary>The current Client in use for this ApplicationProfile.</summary>
            public Guid ClientGUID { get; set; }

            /// <summary>The current Language in use for this ApplicationProfile.</summary>
            public string Language { get; set; }

            #region Association GUID Properties (Foreign Keys)

                /// <summary>
                /// The GUID of the profile type of the profile.
                /// </summary>
                public static PropertyInfo<Guid> ProfileTypeGUIDProperty = RegisterProperty<Guid>(p => p.ProfileTypeGUID);
                /// <summary>
                /// The GUID of the profile type of the profile.
                /// </summary>
                public Guid ProfileTypeGUID
                {
                    get { return GetProperty(ProfileTypeGUIDProperty); }
                    set { SetProperty(ProfileTypeGUIDProperty, value); }
                }

                /// <summary>
                /// The GUID of the Language in use with this profile.
                /// </summary>
                public static PropertyInfo<Guid> LanguageGUIDProperty = RegisterProperty<Guid>(p => p.LanguageGUID);
                /// <summary>
                /// The GUID of the Language in use with this profile.
                /// </summary>
                public Guid LanguageGUID
                {
                    get { return GetProperty(LanguageGUIDProperty); }
                    set { SetProperty(LanguageGUIDProperty, value); }
                }

                /// <summary>
                /// The GUID of the Country in use with this profile.
                /// </summary>
                public static PropertyInfo<Guid?> CountryGUIDProperty = RegisterProperty<Guid?>(p => p.CountryGUID);
                /// <summary>
                /// The GUID of the Country in use with this profile.
                /// </summary>
                public Guid? CountryGUID
                {
                    get { return GetProperty(CountryGUIDProperty); }
                    set { SetProperty(CountryGUIDProperty, value); }
                }

                /// <summary>The User GUID of the User associated with this profile.</summary>
                public static PropertyInfo<Guid> UserGUIDProperty = RegisterProperty<Guid>(p => p.UserGUID);
                /// <summary>The User GUID of the User associated with this profile.</summary>
                public Guid UserGUID
                {
                    get { return GetProperty(UserGUIDProperty); }
                    set { SetProperty(UserGUIDProperty, value); }
                }

            #endregion

            /// <summary>The username for the user associated with this profile.</summary>
            public static PropertyInfo<string> UsernameProperty = RegisterProperty<string>(p => p.Username);
            /// <summary>The username for the user associated with this profile.</summary>
            public string Username
            {
                get { return GetProperty(UsernameProperty); }
                set { SetProperty(UsernameProperty, value); }
            }

            /// <summary>The password for the user associated with this profile.</summary>
            public static PropertyInfo<string> PasswordProperty = RegisterProperty<string>(p => p.Password);
            /// <summary>The password for the user associated with this profile.</summary>
            public string Password
            {
                get { return GetProperty(PasswordProperty); }
                private set { SetProperty(PasswordProperty, value); }
            }

            /// <summary>The private key generated for this user to authenticate with.</summary>
            public static PropertyInfo<string> PrivateKeyProperty = RegisterProperty<string>(p => p.PrivateKey);
            /// <summary>The private key generated for this user to authenticate with.</summary>
            public string PrivateKey
            {
                get { return GetProperty(PrivateKeyProperty); }
            }

            /// <summary>A reference to locate the user's home screen or start page for a particular system.</summary>
            public static PropertyInfo<string> HomeScreenProperty = RegisterProperty<string>(p => p.HomeScreen);
            /// <summary>A reference to locate the user's home screen or start page for a particular system.</summary>
            public string HomeScreen
            {
                get { return GetProperty(HomeScreenProperty); }
                set { SetProperty(HomeScreenProperty, value); }
            }

            /// <summary>Whether the Profile is enabled</summary>
            public static PropertyInfo<bool> EnabledProperty = RegisterProperty<bool>(p => p.Enabled);
            /// <summary>Whether the Profile is enabled</summary>
            public bool Enabled
            {
                get { return GetProperty(EnabledProperty); }
                set { SetProperty(EnabledProperty, value); }
            }

            /// <summary>The date of the last successfull login for the user</summary>
            public static PropertyInfo<SmartDate> LastLogonDateTimeProperty = RegisterProperty<SmartDate>(p => p.LastLogonDateTime);
            /// <summary>The date of the last successfull login for the user</summary>
            public SmartDate LastLogonDateTime
            {
                get { return GetProperty(LastLogonDateTimeProperty); }
                set { SetProperty(LastLogonDateTimeProperty, value); }
            }

            /// <summary>A numeric value representing successful logins for a user</summary>
            public static PropertyInfo<long> SuccessfulLogonCountProperty = RegisterProperty<long>(p => p.SuccessfulLogonCount);
            /// <summary>A numeric value representing successful logins for a user</summary>
            public long SuccessfulLogonCount
            {
                get { return GetProperty(SuccessfulLogonCountProperty); }
                set { SetProperty(SuccessfulLogonCountProperty, value); }
            }

            /// <summary>The fullname for this user associated with this profile</summary>
            public static PropertyInfo<string> FullNameProperty = RegisterProperty<string>(p => p.FullName);
            /// <summary>The fullname for this user associated with this profile</summary>
            public string FullName
            {
                get { return String.Concat(GetProperty(FirstnameProperty), " ", GetProperty(LastNameProperty)); }
            }

            /// <summary>The first name for this user associated with this profile</summary>
            public static PropertyInfo<string> FirstnameProperty = RegisterProperty<string>(p => p.Firstname);
            /// <summary>The first name for this user associated with this profile</summary>
            public string Firstname
            {
                get { return GetProperty(FirstnameProperty); }
                set { SetProperty(FirstnameProperty, value); }
            }

            /// <summary>The last name for this user associated with this profile</summary>
            public static PropertyInfo<string> LastNameProperty = RegisterProperty<string>(p => p.Lastname);
            /// <summary>The last name for this user associated with this profile</summary>
            public string Lastname
            {
                get { return GetProperty(LastNameProperty); }
                set { SetProperty(LastNameProperty, value); }
            }

            /// <summary>The email address for the user associated with this profile</summary>
            public static PropertyInfo<string> EMailProperty = RegisterProperty<string>(p => p.EMail);
            /// <summary>The email address for the user associated with this profile</summary>
            public string EMail
            {
                get { return GetProperty(EMailProperty); }
                set { SetProperty(EMailProperty, value); }
            }

            /// <summary>A numeric value representing the number of failed login attempts for a user</summary>
            public static PropertyInfo<int> FailedLoginAttemptsProperty = RegisterProperty<int>(p => p.FailedLoginAttempts);
            /// <summary>A numeric value representing the number of failed login attempts for a user</summary>
            public int FailedLoginAttempts
            {
                get { return GetProperty(FailedLoginAttemptsProperty); }
                set { SetProperty(FailedLoginAttemptsProperty, value); }
            }

            #region Association Properties (Related Objects)

                /// <summary>The contact details of the user associated with this profile</summary>
                public static PropertyInfo<ContactDetails> ContactDetailsProperty = RegisterProperty<ContactDetails>(p => p.ContactDetails);
                /// <summary>The contact details of the user associated with this profile</summary>
                private ContactDetails ContactDetails
                {
                    get
                    {
                        // If we have an associated GUID value but the property hasn't been loaded yet,
                        // load the property otherwise just get the current property
                        if (!FieldManager.FieldExists(ContactDetailsProperty) && UserGUID != Guid.Empty)
                        {
                            // Load the property and notify CSLA that the property has changed
                            LoadProperty(ContactDetailsProperty, ContactDetails.GetByUserGUID(UserGUID));
                            OnPropertyChanged(ContactDetailsProperty);
                            return ReadProperty(ContactDetailsProperty);
                        }
                        else if (FieldManager.FieldExists(ContactDetailsProperty))
                        {
                            // Return the current property
                            return GetProperty(ContactDetailsProperty);
                        }
                        else
                        {
                            ContactDetails = ContactDetails.New();
                            return ContactDetails;
                        }
                    }
                    set
                    {
                        // Set the associated GUID value and the association property (this) value
                        LoadProperty(ContactDetailsProperty, value);
                    }
                }

            #endregion

        #endregion

    }
}
